package com.sh.caryr.erp.service.impl;

import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.sh.caryr.erp.entity.definition.CommonFieldDef;
import com.sh.caryr.erp.entity.enums.*;
import com.sh.caryr.erp.entity.others.StockOperation;
import com.sh.caryr.erp.entity.product.CombNum;
import com.sh.caryr.erp.entity.product.ProductSpec;
import com.sh.caryr.erp.entity.stock.Sku;
import com.sh.caryr.erp.entity.stock.SkuRecord;
import com.sh.caryr.erp.entity.trade.TradeOrder;
import com.sh.caryr.erp.exception.RestServiceException;
import com.sh.caryr.erp.exception.ResultCode;
import com.sh.caryr.erp.mapper.SkuMapper;
import com.sh.caryr.erp.service.IProductSpecService;
import com.sh.caryr.erp.service.ISkuRecordService;
import com.sh.caryr.erp.service.ISkuService;
import com.sh.caryr.erp.util.MyBatisUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements ISkuService {


    @Autowired
    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    private ISkuRecordService skuRecordService;

    @Autowired
    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    private  IProductSpecService productSpecService;

    @Transactional
    @Override
    public void updateSkuByOrderItem(TradeOrder newOrderItem, TradeOrder oldOrderItem) throws Exception {
        // Get Sku List
        List<Sku> skuList = getSkuListProductSpecId(
                newOrderItem != null ? newOrderItem.getProductSpecId() : oldOrderItem.getProductSpecId()
        );
        if (CollectionUtils.isEmpty(skuList)) {
            return;
        }

        //Get StockOperation List
        List<StockOperation> operations = updateSkuAndGetOperations(newOrderItem, oldOrderItem, skuList);
        if (CollectionUtils.isEmpty(operations)) {
            return;
        }

        //Get Sku records
        List<SkuRecord> skuRecordList = this.genSkuRecordByStockOpera(operations);
        if (!skuRecordList.isEmpty()) {
            //--- 1. Persist Sku
            this.updateBatchById(skuList);
            //--- 2. Persist SkuRecord
            skuRecordService.insertBatch(skuRecordList);
        }
    }

    @SuppressWarnings("unchecked")
    private List<Sku> getSkuListProductSpecId(Long productSpecId) {
        Wrapper wrapper = MyBatisUtil.getIsActiveWrapper();
        wrapper.eq(CommonFieldDef.PRO_MAPPING_SPEC_ID, productSpecId);
        return this.selectList(wrapper);
    }

    private List<StockOperation> updateSkuAndGetOperations(TradeOrder newTradeOrder, TradeOrder oldTradeOrder, List<Sku> skuList) throws Exception {
        StockOperation operation = new StockOperation();
        Float lockedAmount = 0f, usableAmountDelta = 0f;
        SkuRecordHandleType handleType = SkuRecordHandleType.LOCK;
        if (oldTradeOrder == null) {
            //新加订单项
            if (newTradeOrder.getStatus() >= OrderStatus.WAIT_RECEIVE.getValue()) {
                // 1. 新加订单项: 发货
                handleType = SkuRecordHandleType.OUT;
                usableAmountDelta = newTradeOrder.getProductSpecAmount();
            } else if (newTradeOrder.getStatus() >= OrderStatus.WAIT_ASSGN_EXP.getValue()) {
                // 2. 新加订单项: 锁定库存
                lockedAmount = newTradeOrder.getProductSpecAmount();
            }
        } else if (newTradeOrder == null) {
            //删除订单项
            if (oldTradeOrder.getStatus() >= OrderStatus.WAIT_RECEIVE.getValue()) {
                // 3.Delete orderItem: Deliver
                throw new RestServiceException(ResultCode.TRADE_DEL_NOT_ALLOWED_STD);
            } else if (oldTradeOrder.getStatus() >= OrderStatus.WAIT_ASSGN_EXP.getValue()) {
                // 4.Delete orderItem: Assigned Logistic but not Deliver yet
                lockedAmount = oldTradeOrder.getProductSpecAmount() * -1;
            }
        } else {
            //更新订单项
            if (oldTradeOrder.getStatus() < OrderStatus.WAIT_ASSGN_EXP.getValue()) {
                //原订单没有锁定库存
                if (newTradeOrder.getStatus() >= OrderStatus.WAIT_ASSGN_EXP.getValue() &&
                        newTradeOrder.getStatus() < OrderStatus.WAIT_RECEIVE.getValue()) {
                    // 5. 更新订单项: 锁定库存
                    lockedAmount = newTradeOrder.getProductSpecAmount();
                } else if (newTradeOrder.getStatus() >= OrderStatus.WAIT_RECEIVE.getValue()) {
                    // 6. 更新订单项: 发货
                    handleType = SkuRecordHandleType.OUT;
                    usableAmountDelta = newTradeOrder.getProductSpecAmount();
                }
            } else if (oldTradeOrder.getStatus() >= OrderStatus.WAIT_ASSGN_EXP.getValue()  //原订单有锁定库存 但还没发货
                    && oldTradeOrder.getStatus() < OrderStatus.WAIT_RECEIVE.getValue()) {
                if (newTradeOrder.getStatus() < OrderStatus.WAIT_RECEIVE.getValue()) {
                    //新订单没发货 更新锁定库存
                    lockedAmount = newTradeOrder.getProductSpecAmount() - oldTradeOrder.getProductSpecAmount();
                } else if (newTradeOrder.getStatus() >= OrderStatus.WAIT_RECEIVE.getValue()) {
                    //新订单发货 更新锁定库存
                    handleType = SkuRecordHandleType.OUT;
                    lockedAmount = oldTradeOrder.getProductSpecAmount() * -1;
                }
            }
        }

        TradeOrder orderItem = newTradeOrder != null ? newTradeOrder : oldTradeOrder;
        operation.setOrderId(orderItem.getTradeId());
        operation.setHandleType(handleType);
        operation.setLockedAmountDelta(lockedAmount);
        operation.setUsableAmountDelta(usableAmountDelta);

        // Get CombNum
        List<CombNum> combNumList = new ArrayList<>();
        if (orderItem.getProductType() == ProductTypeEnum.CONTAINSKU) {
            ProductSpec productSpec = productSpecService.selectById(orderItem.getProductSpecId());
            combNumList = productSpec.getCombNumList();
        }
        return updateSkuAndGetOperations(skuList, operation, combNumList);
    }

    private static List<StockOperation> updateSkuAndGetOperations(List<Sku> skuList, StockOperation stockOperation, List<CombNum> combNumList)
            throws Exception {
        List<StockOperation> operations = new ArrayList<>();
        for (Sku sku : skuList) {
            StockOperation operation = stockOperation.clone();
            if (CollectionUtils.isNotEmpty(combNumList)) {  //If it`s Sku Set
                for (CombNum combNum : combNumList) {  // Amount * CombNumb
                    if (sku.getId().equals(combNum.getSkuId())) {
                        operation.setLockedAmountDelta(stockOperation.getLockedAmountDelta() * combNum.getSkuNum());
                        operation.setUsableAmountDelta(stockOperation.getUsableAmountDelta() * combNum.getSkuNum());
                        break;
                    }
                }
            }

            //Update Sku Quantity
            sku.setLockedAmount(sku.getLockedAmount() + operation.getLockedAmountDelta());
            if (sku.getLockedAmount() < 0) {
                sku.setLockedAmount(0f);
            }
            if (operation.getHandleType().equals(SkuRecordHandleType.LOCK)) {
                sku.setUsableAmount(sku.getUsableAmount() - operation.getLockedAmountDelta());
            } else if (operation.getHandleType().equals(SkuRecordHandleType.OUT) && operation.getUsableAmountDelta() != 0) {
                sku.setUsableAmount(sku.getUsableAmount() - operation.getUsableAmountDelta());
            }

            operation.setSku(sku);
            operations.add(operation);
        }
        return operations;
    }

    private List<SkuRecord> genSkuRecordByStockOpera(List<StockOperation> operations) {
        List<SkuRecord> skuRecordList = new ArrayList<>();
        for (StockOperation operation : operations) {
            skuRecordList.add(genSkuRecord(operation));
        }
        return skuRecordList;
    }

    private SkuRecord genSkuRecord(StockOperation stockOperation) {
        Sku sku = stockOperation.getSku();
        return SkuRecord.builder().
                type(SkuRecordOrderType.TRADE).
                orderId(stockOperation.getOrderId()).
                coco(sku.getCoco()).
                name(sku.getName()).
                code(sku.getCode()).
                skuId(sku.getId()).
                handleAmount(stockOperation.getUsableAmountDelta()).
                usableAmount(sku.getUsableAmount()).
                notGoodAmount(sku.getNotGoodAmount()).
                lockedAmount(sku.getLockedAmount()).
                remark(stockOperation.getOrderId() + "").
                handleType(stockOperation.getHandleType()).build();
    }
}
